package com.ecoolex.discount.sales.core.service;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.util.Date;
import java.util.TimeZone;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.ecoolex.discount.sales.core.external.NihaoPayExternalService;
import com.ecoolex.discount.sales.core.external.pojo.APIOrderRespVO;
import com.ecoolex.discount.sales.core.external.pojo.APIRefundRespVO;
import com.ecoolex.discount.sales.core.external.pojo.APISecurePayRespVO;
import com.ecoolex.discount.sales.core.manager.PaymentOrderManager;
import com.ecoolex.discount.sales.core.manager.PaymentOrderRecordManager;
import com.ecoolex.discount.sales.entity.DiscountOrder;
import com.ecoolex.discount.sales.entity.PaymentOrder;
import com.ecoolex.discount.sales.entity.PaymentOrderRecord;
import com.ecoolex.discount.sales.enums.NihaoPayType;
import com.ecoolex.discount.sales.enums.PaymentOrderRecordOperType;
import com.ecoolex.discount.sales.enums.PaymentOrderRecordResultStatus;
import com.ecoolex.discount.sales.enums.PaymentOrderStatus;
import com.ecoolex.framework.common.enums.ResultCode;
import com.ecoolex.framework.common.exception.IllegalFormatParseException;
import com.ecoolex.framework.common.util.BigDecimalUtil;
import com.ecoolex.framework.common.util.BizAssert;
import com.ecoolex.framework.common.util.Check;

@Service
public class NihaoPayService {
	
	private static final Logger log = LoggerFactory.getLogger(NihaoPayService.class);

	@Autowired
	private NihaoPayExternalService nihaoPayExternalService;
    @Autowired
    private PaymentOrderManager paymentOrderManager;
    @Autowired
    private PaymentOrderRecordManager paymentOrderRecordManager;
    
    private static final String TYPE_DISCOUNT_ORDER = "DO";
    
    public static final String PAYMENT_TYPE = "NihaoPay";
    
    public String pay(Integer nihaoPayType,DiscountOrder order, HttpServletRequest req, HttpServletResponse resp, String createUser) {
    	// 取支付单
    	PaymentOrder paymentOrder = paymentOrderManager.getByBizTypeAndOrderNo(TYPE_DISCOUNT_ORDER,order.getOrderNo());
    	if(Check.isNull(paymentOrder)) {
    		//创建支付订单
    		paymentOrder = new PaymentOrder();
    		paymentOrder.setBizType(TYPE_DISCOUNT_ORDER);
    		paymentOrder.setOrderNo(order.getOrderNo());
			paymentOrder.setPaymentType(PAYMENT_TYPE);
			if (Check.notNull(order.getCurrencyType())) {
				paymentOrder.setPrepaidCurrencyType(order.getCurrencyType());
            } else {
            	paymentOrder.setPrepaidCurrencyType("CNY");
            }
    		paymentOrder.setUserId(order.getUserId());
    		paymentOrder.setPrepaidPrice(order.getTotalPrice());
    		paymentOrder.setStatus(PaymentOrderStatus.PAY_APPLY.real());
    		paymentOrder.setDeleted(PaymentOrder.NOT_DELETED);
    		paymentOrder.setCreateUser(createUser);
    		paymentOrder.setCreateTime(Date.from(Instant.now()));
    		paymentOrder.setUpdateUser(createUser);
    		paymentOrder.setUpdateTime(Date.from(Instant.now()));
    		paymentOrderManager.create(paymentOrder);
    	}else {
    		//失败才能重新发起支付
    		BizAssert.isTrue(paymentOrder.getStatus().equals(PaymentOrderStatus.PAY_FAILED.real()) || 
    			paymentOrder.getStatus().equals(PaymentOrderStatus.PAY_APPLY.real()),
    			ResultCode.BIZ.build(10), "订单已支付,无法发起支付");
    		paymentOrder.setStatus(PaymentOrderStatus.PAY_APPLY.real());
    		paymentOrderManager.updatePaymentOrder(paymentOrder,createUser);
    	}
    	//记录支付日志
    	PaymentOrderRecord log = paymentOrderRecordManager.create(paymentOrder,PAYMENT_TYPE, PaymentOrderRecordOperType.ORDER_APPLY);
    	log.setTransAmount(paymentOrder.getPrepaidPrice());
    	log.setCurrencyType(paymentOrder.getPrepaidCurrencyType());
    	try {
    		String txnAmt = BigDecimalUtil.convertToString(BigDecimalUtil.dollarToCent(paymentOrder.getPrepaidPrice()), 0);
    		//NihaoPay支付
    		String result = nihaoPayExternalService.APISecurePay(req, order.getOrderNo(), txnAmt, paymentOrder.getPrepaidCurrencyType(), NihaoPayType.realValueOf(nihaoPayType).describe(), resp);
    		log.setTransTime(paymentOrder.getCreateTime());
    		log.setResultStatus(PaymentOrderRecordResultStatus.SUCCEED.real());
    		return result;
    	}catch (Exception e) {
    		log.setResultStatus(PaymentOrderRecordResultStatus.FAILED.real());
    		log.setErrorMessage(e.getMessage());
    		//修改支付订单为支付失败
    		paymentOrder.setStatus(PaymentOrderStatus.PAY_FAILED.real());
    		paymentOrderManager.updatePaymentOrder(paymentOrder,createUser);
    		NihaoPayService.log.error("发起支付失败",e);
    		BizAssert.throwBizException("发起支付失败");
    		return null;
		}finally {
			paymentOrderRecordManager.add(log, createUser);
		}
    }
    
    public void orderNotify(HttpServletRequest req, HttpServletResponse response, String createUser) throws Exception{
    	APISecurePayRespVO respVO = nihaoPayExternalService.receiveIPN(response, req);
		PaymentOrder paymentOrder = paymentOrderManager.getByBizTypeAndOrderNo(TYPE_DISCOUNT_ORDER,respVO.getReference());
		BizAssert.isTrue(Check.notNull(paymentOrder),ResultCode.VERIFY.build(10), "支付订单不存在");
		//检查订单支付状态，并且记录操作日志
		PaymentOrderRecord log = paymentOrderRecordManager.create(paymentOrder,PAYMENT_TYPE, PaymentOrderRecordOperType.ORDER_NOTIFY);
		if(respVO.getStatus().equalsIgnoreCase("success")) {
			log.setCurrencyType(respVO.getCurrency());
			log.setTransAmount(BigDecimalUtil.centToDollar(BigDecimal.valueOf(Long.valueOf(respVO.getAmount()))));
			//log.setRmbAmount(BigDecimalUtil.centToDollar(BigDecimal.valueOf(Long.valueOf(respVO.getRmbAmount()))));
			log.setTransNo(respVO.getId());
			log.setTransTime(parseTimeZoneUTCToCST("yyyy-MM-ddHH:mm:ss", respVO.getTime()));
			log.setResultStatus(PaymentOrderRecordResultStatus.SUCCEED.real());
		}else {
			log.setResultStatus(PaymentOrderRecordResultStatus.FAILED.real());
		}
		paymentOrderRecordManager.add(log, createUser);
		//更新订单
		paymentOrderManager.updatePayStatusAndNotify(paymentOrder,log,createUser);
		//返回给银联服务器http 200  状态码
		response.getWriter().print("ok");
    }
    
    private Date parseTimeZoneUTCToCST(String pattern,String UTCTimeString) {
		try {
			String a1 = UTCTimeString.substring(0, 10);
			String a2 = UTCTimeString.substring(11, 19);
			SimpleDateFormat format = new SimpleDateFormat(pattern);
			format.setTimeZone(TimeZone.getTimeZone("UTC"));
			return format.parse(a1+a2);
		} catch (ParseException e) {
			throw new IllegalFormatParseException(e);
		}
    }
    
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public PaymentOrder checkPayStatus(PaymentOrder paymentOrder,String updateUser) {
    	//不是支付中的数据
    	if(PaymentOrderStatus.PAY_APPLY.notEqual(paymentOrder.getStatus())) {
    		paymentOrderManager.updatePaymentOrder(paymentOrder,updateUser);
            return paymentOrder;
    	}
    	try {
    		APIOrderRespVO orderRespVO = nihaoPayExternalService.checkPayResult(paymentOrder.getOrderNo());
    		// 检查支付订单的状态, 并生成相应记录
            PaymentOrderRecord log = paymentOrderRecordManager.create(paymentOrder,PAYMENT_TYPE,PaymentOrderRecordOperType.ORDER_CHECK);
            log.setTransAmount(BigDecimalUtil.centToDollar(BigDecimal.valueOf(orderRespVO.getAmount())));
            log.setTransNo(orderRespVO.getId());

            if (orderRespVO.getStatus().equalsIgnoreCase("pending")) {
                // 用户支付中
                log.setResultStatus(PaymentOrderRecordResultStatus.ONGOING.real());
            } else if (orderRespVO.getStatus().equalsIgnoreCase("success")) {
                // 用户支付成功
                log.setTransTime(parseTimeZoneUTCToCST("yyyyMMddHHmmss", orderRespVO.getTime()));
                log.setResultStatus(PaymentOrderRecordResultStatus.SUCCEED.real());
            } else {
                // 其他原因全为失败
                log.setResultStatus(PaymentOrderRecordResultStatus.FAILED.real());
            }
            // 记录调用详情
            paymentOrderRecordManager.add(log, updateUser);
            
            // 更新订单
            paymentOrderManager.updatePayStatusAndNotify(paymentOrder, log, updateUser);
		} catch (Exception e) {
			NihaoPayService.log.error("查询订单异常"+e);
		}
    	return paymentOrder;
    }
    
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public boolean refundApply(String orderNo,BigDecimal refundPrice,String updateUser) {
    	PaymentOrder paymentOrder = paymentOrderManager.getByBizTypeAndOrderNo(TYPE_DISCOUNT_ORDER,orderNo);
    	BizAssert.isTrue(Check.notNull(paymentOrder),ResultCode.BIZ.build(10), "未找到支付订单，无法发起退款");
    	// 已支付或失败才能发起
        BizAssert.isTrue(PaymentOrderStatus.PAY_SUCCEED.equal(paymentOrder.getStatus())
            || PaymentOrderStatus.REFUND_FAILED.equal(paymentOrder.getStatus()), ResultCode.BIZ.build(11), "订单必须已支付, 才能发起退款");
        // 变更状态为发起退款
        paymentOrder.setStatus(PaymentOrderStatus.REFUND_APPLY.real());
        paymentOrder.setRefundPrice(refundPrice);
        paymentOrderManager.updatePaymentOrder(paymentOrder,updateUser);
        
        // 创建日志
        PaymentOrderRecord log = paymentOrderRecordManager.create(paymentOrder,PAYMENT_TYPE, PaymentOrderRecordOperType.REFUND_APPLY);
        
        try {
        	String txnAmt = BigDecimalUtil.convertToString(BigDecimalUtil.dollarToCent(refundPrice), 0);
			APIRefundRespVO refundRespVO = nihaoPayExternalService.APIRefund(paymentOrder.getPaymentNo(), paymentOrder.getPrepaidCurrencyType(), txnAmt);
			if(refundRespVO.getStatus().equalsIgnoreCase("success")) {
				log.setTransAmount(BigDecimalUtil.centToDollar(BigDecimal.valueOf(Long.parseLong(txnAmt))));
				log.setTransNo(refundRespVO.getId());
				log.setResultStatus(PaymentOrderRecordResultStatus.SUCCEED.real());
				//paymentOrder.setRefundOrderNo(orderNo);
				paymentOrder.setStatus(PaymentOrderStatus.REFUND_SUCCEED.real());
			}else {
				log.setResultStatus(PaymentOrderRecordResultStatus.FAILED.real());
				paymentOrder.setStatus(PaymentOrderStatus.REFUND_FAILED.real());
			}
			paymentOrderManager.updatePaymentOrder(paymentOrder,updateUser);
		} catch (Exception e) {
			log.setResultStatus(PaymentOrderRecordResultStatus.FAILED.real());
			log.setErrorMessage(e.getMessage());
			paymentOrder.setStatus(PaymentOrderStatus.REFUND_FAILED.real());
			paymentOrderManager.updatePaymentOrder(paymentOrder,updateUser);
		}finally {
			//调用记录日志
			paymentOrderRecordManager.add(log, updateUser);
		}
        if(PaymentOrderRecordResultStatus.SUCCEED.equal(log.getResultStatus())) {
        	return true;
        }
        return false;
    }
    
}
